﻿using System;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using Common;

namespace CoreServiceLibrary
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class CoreService : ICoreService
    {
        private DataContext context = null;
        private const int ServiceID = 0;

        public CoreService()
        {
            context = new DataContext();
            Logger.type = "core";
        }

        public Response SendMesssage(string sender, string reciever, string title, string text, string attachmentID)
        {
            Response response = new Response();
            response.ServiceID = ServiceID;
            try
            {
                MailMessage message = new MailMessage()
                {
                    Read = false,
                    AttachmentID = attachmentID,
                    Reciever = reciever,
                    Sender = sender,
                    Text = text,
                    Title = title,
                };

                lock (context)
                {
                    context.Messages.Add(message);
                    context.SaveChanges();
                }
            }
            catch (SqlException se)
            {
                Logger.Write(se, "Exeption in " + this.GetType().Name + "." + MethodBase.GetCurrentMethod().Name + " method");
                response.Error = new Error()
                {
                    TargetSite = se.TargetSite.Name,
                    Type = ErrorTypes.InternalError,
                    Details = se.Message
                };
            }
            catch (Exception ex)
            {
                Logger.Write(ex, "Exeption in " + this.GetType().Name + "." + MethodBase.GetCurrentMethod().Name + " method");
                response.Error = new Error()
                {
                    TargetSite = ex.TargetSite.Name,
                    Type = ErrorTypes.InternalError,
                    Details = ex.Message
                };
            }
            return response;
        }

        public Response GetRecievedMessages(string userID, int pageIndex, int pageSize)
        {
            Response response = new Response();
            response.ServiceID = ServiceID;

            try
            {
                lock (context)
                {
                    var messages = (from m in context.Messages where m.Reciever == userID orderby m.CreationTime descending select m);
                    if (messages.Count() == 0)
                    {
                        response.Error = new Error()
                        {
                            Details = "No incoming messages found for user ID " + userID + "'",
                            TargetSite = MethodBase.GetCurrentMethod().Name,
                            Type = ErrorTypes.ObjectNotFound
                        };
                    }
                    else
                    {
                        response.TotalResultsCount = messages.Count();
                        if (pageIndex != -1 && pageSize != -1)
                        {
                            response.Result.AddRange(messages.Skip(pageIndex * pageSize).Take(pageSize));
                        }
                        else
                        {
                            response.Result.AddRange(messages);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Write(ex, "Exeption in " + this.GetType().Name + "." + MethodBase.GetCurrentMethod().Name + " method");
                response.Error = new Error()
                {
                    TargetSite = ex.TargetSite.Name,
                    Type = ErrorTypes.InternalError,
                    Details = ex.Message
                };
            }
            return response;
        }

        public Response UploadFile(string fileName, string uploaderID, string contentType)
        {
            Response response = new Response();
            response.ServiceID = ServiceID;
            try
            {
                Attachment attachment = new Attachment()
                {
                    FileName = fileName,
                    UploaderID = uploaderID,
                    ContentType = contentType
                };

                lock (context)
                {
                    context.Attachments.Add(attachment);
                    context.SaveChanges();
                }
                response.Result.Add(attachment);
            }
            catch (IOException io)
            {
                Logger.Write(io, "Exeption in " + this.GetType().Name + "." + MethodBase.GetCurrentMethod().Name + " method");
                response.Error = new Error()
                {
                    TargetSite = io.TargetSite.Name,
                    Type = ErrorTypes.InternalError,
                    Details = io.Message
                };
            }
            catch (Exception ex)
            {
                Logger.Write(ex, "Exeption in " + this.GetType().Name + "." + MethodBase.GetCurrentMethod().Name + " method");
                response.Error = new Error()
                {
                    TargetSite = ex.TargetSite.Name,
                    Type = ErrorTypes.InternalError,
                    Details = ex.Message
                };
            }
            return response;
        }

        public Response DownloadFile(string fileID)
        {
            Response response = new Response();
            response.ServiceID = ServiceID;
            try
            {
                lock(context)
                {
                    var file = (from a in context.Attachments where a.ID == fileID select a).SingleOrDefault();
                    if(file == null)
                    {
                        response.Error = new Error()
                        {
                            Details = "Requested file not found in the filestore. Check the ID and try again",
                            TargetSite = MethodBase.GetCurrentMethod().Name,
                            Type = ErrorTypes.ObjectNotFound
                        };
                    }
                    else
                    {
                        response.Result.Add(file);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Write(ex, "Exeption in " + this.GetType().Name + "." + MethodBase.GetCurrentMethod().Name + " method");
                response.Error = new Error()
                {
                    TargetSite = ex.TargetSite.Name,
                    Type = ErrorTypes.InternalError,
                    Details = ex.Message
                };
            }
            return response;
        }

        /*
        private void SaveFile(string FileID, string FileName, Stream InputStream)
        {
            string path = Path.Combine(UploadDirectory, FileID);
            if (!Directory.Exists(path))
            {
                try
                {
                    var di = Directory.CreateDirectory(path);
                    Logger.Write("Directory successfully created");
                }
                catch (Exception ex)
                {
                    Logger.Write("Unable to create file upload directory, More information: \n" + ex.Message);
                    throw new IOException("Failed to create nessesary directories. Please try again later");
                }
            }
            try
            {
                FileStream OutputStream = new FileStream(Path.Combine(path, FileName), FileMode.CreateNew, FileAccess.ReadWrite);
                //Write 1KB
                int lenght = 256;
                byte[] buffer = new byte[lenght];
                while (InputStream.Read(buffer, 0, lenght) > 0)
                {
                    OutputStream.Write(buffer, 0, lenght);
                }
                if (OutputStream.Length != InputStream.Length)
                {
                    throw new IOException("Input and Output Stream length differ");
                }
                OutputStream.Close();
                InputStream.Close();
            }
            catch (IOException io)
            {
                Logger.Write("Unable to create file on the disk, More information: \n" + io.Message);
                throw new IOException("Failed to create file on the disk. Please try again later", io);
            }
        }*/

        public Response GetMessageDetails(string messageID)
        {
            Response response = new Response();
            response.ServiceID = ServiceID;

            try
            {
                lock (context)
                {
                    var message = (from m in context.Messages where m.ID == messageID select m).SingleOrDefault();
                    if (message == null)
                    {
                        response.Error = new Error()
                        {
                            Details = "Message with ID " + messageID + "' not found",
                            TargetSite = MethodBase.GetCurrentMethod().Name,
                            Type = ErrorTypes.ObjectNotFound
                        };
                    }
                    else
                    {
                        lock (context)
                        {
                            message.Read = true;
                            context.SaveChanges();
                        }
                        response.Result.Add(message);
                    }
                }
            }
            catch (Exception ex)
            {
                //Logger.Write(ex, "Exeption in " + this.GetType().Name + "." + MethodBase.GetCurrentMethod().Name + " method");
                response.Error = new Error()
                {
                    TargetSite = ex.TargetSite.Name,
                    Type = ErrorTypes.InternalError,
                    Details = ex.Message
                };
            }
            return response;
        }

        public Response GetSentMessages(string userID, int pageIndex, int pageSize)
        {
            Response response = new Response();
            response.ServiceID = ServiceID;

            try
            {
                lock (context)
                {
                    var messages = (from m in context.Messages where m.Sender == userID select m);
                    if (messages.Count() == 0)
                    {
                        response.Error = new Error()
                        {
                            Details = "No outgoing messages found for user ID " + userID + "'",
                            TargetSite = MethodBase.GetCurrentMethod().Name,
                            Type = ErrorTypes.ObjectNotFound
                        };
                    }
                    else
                    {
                        response.TotalResultsCount = messages.Count();
                        if (pageIndex != -1 && pageSize != -1)
                        {
                            response.Result.AddRange(messages.Skip(pageIndex * pageSize).Take(pageSize));
                        }
                        else
                        {
                            response.Result.AddRange(messages);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //Logger.Write(ex, "Exeption in " + this.GetType().Name + "." + MethodBase.GetCurrentMethod().Name + " method");
                response.Error = new Error()
                {
                    TargetSite = ex.TargetSite.Name,
                    Type = ErrorTypes.InternalError,
                    Details = ex.Message
                };
            }
            return response;
        }
    }
}